package util

import (
	"cke.io/ckectl/app/apis"
	"cke.io/ckectl/app/apis/v1alpha1"
	"cke.io/ckectl/app/constants"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"github.com/sirupsen/logrus"
	"math/rand"
	"net/http"
	"strings"
	"sync"
	"time"
)

var LogIdMap map[string]int
var LogCache []apis.ComponentLog
var MapLock sync.Mutex
var CacheLock sync.Mutex

type LogChan struct {
	Log   string
	Final bool
}

//是否考虑并发问题
func init() {
	if LogIdMap == nil {
		LogIdMap = make(map[string]int)
	}
}

//Send logs when cache size >= constants.LogCacheSize or final is true.
func SendComponentLog(ckeCluster *v1alpha1.CkeCluster, curNode *v1alpha1.CkeNode, component *v1alpha1.CkeComponent,
	address string, port int, suffix string, action string, logChan chan LogChan, done chan bool) {
	clusterId := ckeCluster.ObjectMeta.Name
	nodeName := curNode.ObjectMeta.Name
	componentName := component.ObjectMeta.Name

	logId := 0
	MapLock.Lock()
	if _, ok := LogIdMap[suffix]; ok {
		logId = LogIdMap[suffix]
	}
	MapLock.Unlock()

	var componentLog apis.ComponentLog
	for {
		select {
		case log := <-logChan:
			componentLog = apis.ComponentLog{
				ClusterID:     clusterId,
				NodeName:      nodeName,
				ComponentName: componentName,
				TimeStamp:     time.Now().String(),
				LogContent:    log.Log,
				LogId:         logId,
				Suffix:        suffix,
				Action:        action,
			}
			logId++
			CacheLock.Lock()
			LogCache = append(LogCache, componentLog)
			CacheLock.Unlock()
			MapLock.Lock()
			LogIdMap[suffix] = logId
			MapLock.Unlock()
			CacheLock.Lock()
			if (len(LogCache) >= constants.LogCacheSize) || log.Final || strings.Contains(log.Log, "FORCE_SEND_LOG") {
				logCacheBytes, err := json.Marshal(LogCache)
				if err != nil {
					logrus.Errorf("Marshal logCache failed: %v", err)
					return
				} else {
					tr := &http.Transport{
						TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
					}
					client := &http.Client{Transport: tr}
					url := fmt.Sprintf("http://%s:%d/log", address, port)
					res, err1 := client.Post(url, "application/json", strings.NewReader(string(logCacheBytes)))
					if res != nil && res.StatusCode == 200 {
						defer res.Body.Close()
					} else {
						if err1 != nil {
							logrus.Errorf("post component log failed: %v", err1)
							return
						}
						if res != nil {
							logrus.Errorf("post component log failed, code: %d", res.StatusCode)
							defer res.Body.Close()
							return
						}
					}
					//clear
					LogCache = []apis.ComponentLog{}
				}
			}
			CacheLock.Unlock()
			if log.Final {
				done <- true
				return
			}
		}
	}
}

// RandString 生成随机字符串
func RandString(len int) string {
	var r *rand.Rand
	r = rand.New(rand.NewSource(time.Now().Unix()))
	bytes := make([]byte, len)
	for i := 0; i < len; i++ {
		b := r.Intn(26) + 97
		bytes[i] = byte(b)
	}
	return string(bytes)
}

//func SendComponentLog(ckeCluster v1alpha1.CkeCluster, curNode v1alpha1.CkeNode, component v1alpha1.CkeComponent,
//	log string, address string, port int, suffix string, action string, final bool) {
//	clusterId := ckeCluster.ObjectMeta.Name
//	nodeName := curNode.ObjectMeta.Name
//	componentName := component.ObjectMeta.Name
//
//	logId := 0
//	if _, ok := LogIdMap[suffix]; ok {
//		logId = LogIdMap[suffix]
//	}
//
//	componentLog := apis.ComponentLog{
//		ClusterID:     clusterId,
//		NodeName:      nodeName,
//		ComponentName: componentName,
//		TimeStamp:     time.Now().String(),
//		LogContent:    log,
//		LogId:         logId,
//		Suffix:        suffix,
//		Action:        action,
//	}
//	logId++
//	LogCache = append(LogCache, componentLog)
//	LogIdMap[suffix] = logId
//
//	if (len(LogCache) >= constants.LogCacheSize) || final {
//		logCacheBytes, err := json.Marshal(LogCache)
//		if err != nil {
//			logrus.Errorf("Marshal logCache failed: %v", err)
//			return
//		} else {
//			tr := &http.Transport{
//				TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
//			}
//			client := &http.Client{Transport: tr}
//			url := fmt.Sprintf("http://%s:%d/log", address, port)
//			res, err1 := client.Post(url, "application/json", strings.NewReader(string(logCacheBytes)))
//			if res != nil && res.StatusCode == 200 {
//				defer res.Body.Close()
//			} else {
//				if err1 != nil {
//					logrus.Errorf("post component log failed: %v", err1)
//					return
//				}
//				if res != nil {
//					logrus.Errorf("post component log failed, code: %d", res.StatusCode)
//					defer res.Body.Close()
//					return
//				}
//			}
//			//clear
//			LogCache = []apis.ComponentLog{}
//		}
//	}
//}
